파이썬으로 특정 api서비스를 이용하는 방법은 http 통신으로 진행되게 됩니다. 파이썬의 간단한 코드는 해당 부분을 모듈로 잘 만들어 두었기 때문이죠.
우리는 업체에서 제공하는 가이드라인과 모듈을 이용해 원하는 기능을 원격으로 활용할 수 있습니다. 때문에 서버와의 통신에서 requests가 자주 사용되는 것을 볼 수 있습니다.
👉 tinify를 이용한 이미지 압축 프로그램 만들기 도전
finypng의 api서비스를 이용하는 과정에서도 http통신을 통한 서버와의 연결, 그리고 이미지 압축파일의 전송이 이루어지게 됩니다.
제가 겪은 오류 상황은 vscode, jupyter notebook의 스크립트에서는 문제없이 작동되던 코드가 pyinstaller로 exe파일을 만들기만 하면, finify의 .from_file() 함수에서 먹통이 되는 현상입니다.
스크립트에서 아무 오류가 없었기에 답답한 마음으로 이것저것 살펴봤습니다. 여러가지 의심이 되는 부분들이 있다면 수정하면 되는데, 갈피를 잡기가 어렵게만 느껴졌습니다.
의심되는 부분 정리
당시에 의심되어 살펴보던 부분들에 대한 내용입니다.
- 코드 문법 확인
- pyinstaller 모듈에 대한 설정 부분
- tinify 모듈에 대한 이해
- 작업환경에 대한 점검
- 오류문구를 확인하기 위한 코딩 & 오류 확인
1️⃣ 코드 문법 확인
항상 가장 먼저 확인하게 되는 부분이 코드 문법인 것 같습니다. 내가 작성한 스크립트에 오류가 없는지를 살펴보게 됩니다. 물론, 테스트 실행에서 오류가 발생되지 않았지만 다시금 점검하게 되는 것 같습니다.
역시나 여기서는 오류가 발생하지 않았습니다. 단지, 쓸데없는 코드들을 제거하고 의미없이 장황했던 코드를 정리하긴 했습니다.
2️⃣ pyinstaller 모듈 설정부분
이 부분은 참, 이야기할게 많은 부분이기도 하네요. 스크립트에서 오류가 발생되지 않았기 때문에 당연히 pyinstaller가 아니면 tinify에 문제가 있을 것으로 추측했습니다.
두 모듈에서 문제가 없다면, 두 모듈의 호환성에서 문제가 발생한 것이 아닐까 생각했습니다. pyinstaller의 exe파일을 만드는 과정에서 특정 모듈이 포함되지 않거나, 오류가 발생할 수 있을 것이라는 생각이었습니다.
위 추측을 해결하기 위해 구글링과 공식문서를 찾아보기 시작합니다. pyinstaller의 spec파일에서의 설정, 보안관련 설정등 다양한 설정들을 시도했습니다. 오류를 해결하고 난 후에는 설정의 문제가 아니란 것을 알았죠.
3️⃣ tinify 모듈에 대한 이해
여러 추측을 검증하는 과정에서 지쳐가게 됩니다. 차라리 관련 코드를 내가 만들어야 겠다는 생각에 도달합니다. 어차피 모듈에서 해당 함수만 사용하면 되니까요.
아나콘다 환경을 베이스로 하고 있기 때문에 설치된 모듈을 찾아갑니다. 아나콘다 폴더에서 “lib > site-packages > tinify” 경로로 찾을 수 있습니다.
여러 파일을 만날 수 있는데, 지금부터 모험이 시작됩니다. 각각의 .py파일에서 코드들을 살피며 tinify.from_file()에 관련된 내용을 확인합니다.
결론부터 이야기하면, 굳이 하지 않다도 되는 행동이었습니다. 비슷한 상황이 발생되도 이런 행동은 다시 하지 않을 것 같네요. 좋은 구경이었습니다.
4️⃣ 작업환경에 대한 점검
개인적으로 가상환경을 사용하지 않고 있습니다. 매번 환경으로 조성하는게 귀찮기도 하고, 특별한 목적으로 코딩을 하는 것은 아니기 때문입니다.
다시 말해, 모든 모듈과 패키지가 같이 설치되어 있습니다. 이런 환경에서는 모듈끼리의 오류가 발생할 수 있다는 것을 어디선가 들었습니다. 주워듣고 배운게 무섭습니다.
깨끗한 환경에서 테스트를 진행해 봅니다. 간혹 사용하던 vmware환경에서 pyisntaller를 실행해 봅니다. 윈도우자체에서도 오류가 있을까 하는 생각에 vmware를 사용했습니다.
파이썬 가상환경을 조성하면 저와같은 행동을 할 필요는 없겠죠. 결론은 똑같은 증상이 나타났습니다. 이 추측은 원인이 아니었던 것입니다.
5️⃣ 오류문구를 확인하기 위한 코딩 & 오류 확인
‘진작에 오류문구를 확인했어야지.’라는 생각, 제 3자라면 할 수 있습니다. 저도 했으니까요. 반성의 시간이었습니다.
스크립트에서 오류가 없었기 때문에 바로 qtdesigner를 통해 ui를 만들었습니다. 그리고 연결 후, pyinstaller를 통해 exe를 만들었죠. 그리고 test에서 먹통이 됩니다. 당연히 pyinstaller에는 noconsole로 처음 진행했습니다.
- pyinstaller 옵션
- -F : exe파일 하나로 만듦
- –noconsole : exe파일 실행할 때 콘솔을 띄우지 않음
- pyinstaller -F –noconsole 파일경로 및 파일명
그렇다면 console을 띄우면 오류가 뜰 것이라 생각했습니다. 그런데, 코드에 try except를 사용했습니다. 예외처리를 통해 전체가 잘 진행될 수 있도록 말이죠.
개인적으로 생각한 오류메시지는 except를 통해 textbrowser에 표시되도록 했습니다. 스크립트에서 특별한 오류가 없었으니 괜찮을 거라 생각했습니다.
첫번째 시도, pyinstaller에서 console을 띄웁니다. –noconsole 옵션을 제거하고 진행합니다. 프로그램을 실행하면 콘솔창과 함께 메시지가 출력됩니다.
부가적으로 코드진행상황이 표시될 수 있게 print()도 추가했습니다. 보고싶던 error메시지가 출력되지 않습니다.
두번째 시도, try except를 제거하고 단일 코드로 진행합니다. 아마도 try except를 통해 오류가 있어 넘어갔을게 분명하기 때문입니다.
pyinstaller를 실행하고 콘솔창을 확인합니다. 특별한 문제가 나타나지 않습니다. 당시 기억에는 그랬습니다.
세번째 시도, tinify.from_file() 코드만 진행될 수 있는 스크립트를 만들어 테스트를 진행합니다. 스크립트만 테스트 했을 때는 별다른 오류가 나타나지 않았습니다. 당연하지만 기가 막힐 노릇입니다.
오류를 확인해야 문제를 해결하는데 작성한 코드가 너무 깔끔하게 진행됩니다. pyinstaller를 통해 exe를 만들어 확인합니다.
콘솔창이 0.1초만에 사라집니다. 찾았습니다. 왜 위에서 진행한 콘솔에서는 메시지를 확인하지 못했는지 이해할 수 없지만, 이 단계에서는 중요한 것이 아닙니다. 이제 문제를 해결하면 되니까요.
◼ 등장한 error메시지 전문
- tinify.errors.ConnectionError : Error while connecting: Could not find a suitable TLS CA certificate bundle, invalid path: 인증서 경로
- 관련 지식이 없다보니 미친듯이 구글링을 시작합니다.
◼ 인증서 관련 오류, requests cacertificate 관련 이슈.
- requests cacertificate관련 이슈는 생각보다 많았습니다. 이슈가 많으면 해결책을 제시하는 사람들도 많습니다. 도움이 됩니다.
- 해당 이슈의 핵심은 신뢰되는 인증서가 없다는 것입니다.
- tinify 모듈이 있는 폴더에는 인증서가 존재합니다. pyinstaller로 exe를 만드는 과정에서 인증서가 누락되지 않았나 추측할 수 있습니다.
✔ 제시된 해결책은 인증서를 exe파일과 함께 둔다는 것이었습니다. tinify에 있는 인증서를 exe파일과 같은 폴더로 붙여넣기를 했습니다. 해결되지 않았습니다.
✔ 인증서 자체 오류거나 인증서 경로의 문제라 생각합니다.
- 인증서 자체 문제라면, 파일질라에서 제공되는 인증서를 준비했습니다.
- 경로의 문제라면, 코드를 추가했습니다.
- os.environ[‘REQUESTS_CA_BUNDLE’] = os.path.join(os.path.dirname(sys.argv[0]), ‘cacert.pem’)
🔆 드디어 문제가 해결됐습니다. 인증서를 exe파일과 같은 폴더에 두었고, 코드를 통해 해당 인증서를 이용하라고 지시했습니다. 관련 이슈에 대한 이해도는 거의 없다고 생각하지만, 어찌어찌 문제는 해결할 수 있었습니다.
📌 requests cacertificate 이슈(+pyinstaller) 내용 정리
- pyinstaller를 이용해 exe파일을 만드는 과정에서 인증서에 관련된 문제가 발생.
- 인증서파일을 exe폴더에 함께 둔다.
- 소스코드에 인증서 경로를 지정해 준다.
- os.environ[‘REQUESTS_CA_BUNDLE’] = os.path.join(os.path.dirname(sys.argv[0]), ‘cacert.pem’)
➕ 추가로 pyinstaller utf-8 인코딩 문제로 만났습니다. pyinstaller로 만든 exe를 cmd에서 실행 했을 때 발생될 수 있는 문제라고 합니다. 그냥 exe로 실행하면 괜찮다고 하네요.
➕ 스크립트에서 문제가 없어서 main.py를 통해 해당 스크립트를 import하는 형식으로 exe를 만들어 봤습니다. 당연하게도 문제는 해결되지 않았습니다.
➕ 빠르게 사라지는 콘솔창을 보기위해 녹화를 이용했습니다. 아마 더 좋은 방법이 존재하겠지만 어쩔 수 없었습니다. 급하면 가장 먼저 떠오르는 생각으로 행동하게 되니까요. 혹여나 여러분도 비슷한 상황이 발생되면 녹화를 이용해보세요. 생각보다 괜찮습니다.😅
저도 이러한 문제로 막혔다가 해결하였습니다.
제 노션페이지입니다. 참고하세요.
https://phrygian-primula-e45.notion.site/CA-tinify-0d258b93c4f04ed38bf1d00aa0b350b5?pvs=4